﻿using System;
using SFML.Graphics;

namespace Transformable_Engine_v2.Engine.Transformable_Math.Geometry
{
    public class TE_Rectangle
    {
        public enum Alignment
        {
            /// <summary>
            /// X - -
            /// - - -
            /// - - -
            /// </summary>
            TopLeft,
            /// <summary>
            /// - X -
            /// - - -
            /// - - -
            /// </summary>
            TopMiddle,
            /// <summary>
            /// - - X
            /// - - -
            /// - - -
            /// </summary>
            TopRight,
            /// <summary>
            /// - - -
            /// X - -
            /// - - -
            /// </summary>
            CenterLeft,
            /// <summary>
            /// - - -
            /// - X -
            /// - - -
            /// </summary>
            CenterMiddle,
            /// <summary>
            /// - - -
            /// - - X
            /// - - -
            /// </summary>
            CenterRight,
            /// <summary>
            /// - - -
            /// - - -
            /// X - -
            /// </summary>
            BottomLeft,
            /// <summary>
            /// - - -
            /// - - -
            /// - X -
            /// </summary>
            BottomMiddle,
            /// <summary>
            /// - - -
            /// - - -
            /// - - X
            /// </summary>
            BottomRight,
        }

        #region Coordinates
        /// <summary>
        /// See Alignment enum for more information
        /// </summary>
        public TE_Vector2 TopLeft
        {
            get { return new TE_Vector2(X, Y);}
        }

        /// <summary>
        /// See Alignment enum for more information
        /// </summary>
        public TE_Vector2 TopMiddle
        {
            get { return new TE_Vector2(X + Width / 2, Y);}
        }

        /// <summary>
        /// See Alignment enum for more information
        /// </summary>
        public TE_Vector2 TopRight
        {
            get { return new TE_Vector2(X + Width, Y);}
        }

        /// <summary>
        /// See Alignment enum for more information
        /// </summary>
        public TE_Vector2 CenterLeft
        {
            get { return new TE_Vector2(X, Y + Height / 2);}
        }

        /// <summary>
        /// See Alignment enum for more information
        /// </summary>
        public TE_Vector2 CenterMiddle
        {
            get { return new TE_Vector2(X + Width / 2, Y + Height / 2);}
        }

        /// <summary>
        /// See Alignment enum for more information
        /// </summary>
        public TE_Vector2 CenterRight
        {
            get { return new TE_Vector2(X + Width, Y + Height / 2);}
        }

        /// <summary>
        /// See Alignment enum for more information
        /// </summary>
        public TE_Vector2 BottomLeft
        {
            get { return new TE_Vector2(X, Y + Height);}
        }

        /// <summary>
        /// See Alignment enum for more information
        /// </summary>
        public TE_Vector2 BottomMiddle
        {
            get { return new TE_Vector2(X + Width / 2, Y + Height);}
        }

        /// <summary>
        /// See Alignment enum for more information
        /// </summary>
        public TE_Vector2 BottomRight
        {
            get { return new TE_Vector2(X + Width, Y + Height);}
        }

        /// <summary>
        /// Gets the vector2 representing the Width, Height part of the rectangle
        /// </summary>
        public TE_Vector2 Size
        {
            get { return new TE_Vector2(Width, Height); }
        }

        /// <summary>
        /// Gets the vector representing the X, Y part of the rectangle
        /// </summary>
        public TE_Vector2 Position
        {
            get { return new TE_Vector2(X, Y); }
        }
        #endregion

        /// <summary>
        /// Left coordinate of the rectangle
        /// </summary>
        public float Left { get { return X; } }
        /// <summary>
        /// Right coordinate of the rectangle
        /// </summary>
        public float Right { get { return X + Width; } }
        /// <summary>
        /// Top coordinate of the rectangle
        /// </summary>
        public float Top { get { return Y; } }
        /// <summary>
        /// Bottom coordinate of the rectangle
        /// </summary>
        public float Bottom { get { return Y + Height; } }

        /// <summary>
        /// Top left X component
        /// </summary>
        public float X { get; set; }
 
        /// <summary>
        /// Top right Y component
        /// </summary>
        public float Y { get; set; }
 
        /// <summary>
        /// Width of the rectangle
        /// </summary>
        public float Width { get; set; }
 
        /// <summary>
        /// Height of the rectangle
        /// </summary>
        public float Height { get; set; }

        /// <summary>
        /// Rectangle with [0, 0, 0, 0] size
        /// </summary>
        public static TE_Rectangle Zero
        {
            get { return new TE_Rectangle(0, 0, 0, 0); }
        }

        public TE_Rectangle FlipHorizontally
        {
            get { return new TE_Rectangle(-X - Width, Y, Width, Height); }
        }
        public TE_Rectangle FlipVertically
        {
            get { return new TE_Rectangle(X, -Y - Height, Width, Height); }
        }

        /// <summary>
        /// Creates a new instance of the Rectangle class
        /// </summary>
        /// <param name="x">X component</param>
        /// <param name="y">Y component</param>
        /// <param name="width">Width component</param>
        /// <param name="height">Height component</param>
        /// <param name="alignment">Alignment of the rectangle</param>
        public TE_Rectangle(float x, float y, float width, float height, Alignment alignment = Alignment.TopLeft)
        {
            switch(alignment) 
            {
                case Alignment.TopLeft:
                    //Do nothing
                    break;
                case Alignment.TopMiddle:
                    x -= width/2;
                    break;
                case Alignment.TopRight:
                    x -= width;
                    break;
                case Alignment.CenterLeft:
                    y -= height/2;
                    break;
                case Alignment.CenterMiddle:
                    x -= width/2;
                    y -= height/2;
                    break;
                case Alignment.CenterRight:
                    x -= width;
                    y -= height/2;
                    break;
                case Alignment.BottomLeft:
                    y -= height;
                    break;
                case Alignment.BottomMiddle:
                    x -= width/2;
                    y -= height;
                    break;
                case Alignment.BottomRight:
                    x -= width;
                    y -= height;
                    break;
                default:
                    throw new ArgumentOutOfRangeException("alignment");
            }

            X = x;
            Y = y;
            Width = width;
            Height = height;
        }

        /// <summary>
        /// Creates a new instance of the Rectangle class
        /// </summary>
        /// <param name="position">X and Y component</param>
        /// <param name="width">Width component</param>
        /// <param name="height">Height component</param>
        /// <param name="alignment">Alignment of the rectangle</param>
        public TE_Rectangle(TE_Vector2 position, float width, float height, Alignment alignment = Alignment.TopLeft) : 
            this(position.X, position.Y, width, height, alignment)
        {
            
        }

        /// <summary>
        /// Creates a new instance of the Rectangle class
        /// </summary>
        /// <param name="x">X component</param>
        /// <param name="y">Y component</param>
        /// <param name="size">Width and Height component</param>
        /// <param name="alignment">Alignment of the rectangle</param>
        public TE_Rectangle(float x, float y, TE_Vector2 size, Alignment alignment = Alignment.TopLeft) : 
            this(x, y, size.X, size.Y, alignment)
        {
            
        }

        /// <summary>
        /// Creates a new instance of the Rectangle class
        /// </summary>
        /// <param name="position">X and Y component</param>
        /// <param name="size">Width and Height component</param>
        /// <param name="alignment">Alignment of the rectangle </param>
        public TE_Rectangle(TE_Vector2 position, TE_Vector2 size, Alignment alignment = Alignment.TopLeft) : 
            this(position.X, position.Y, size.X, size.Y, alignment)
        {
            
        }

        /// <summary>
        /// Creates a new instance of the Rectangle class with all its properties set to 0
        /// </summary>
        /// <param name="area">Rectangle to copy</param>
        public TE_Rectangle(TE_Rectangle area)
            : this(area.X, area.Y, area.Width, area.Height)
        {
            
        }

        public TE_Rectangle()
            : this(0, 0, 0, 0)
        {
        }

        public TE_Rectangle ToGridBound()
        {
            return new TE_Rectangle(X * Game.Options.GridSize, Y * Game.Options.GridSize, Width * Game.Options.GridSize, Height * Game.Options.GridSize);
        }

        /// <summary>
        /// Convert a rectangle to a SFML native type
        /// </summary>
        /// <returns>Return corresponding IntRect</returns>
        public IntRect ToIntRect()
        {
            return new IntRect((int) X, (int) Y, (int) Width, (int) Height);
        }

        /// <summary>
        /// Adds a vector2 to the rectangle
        /// </summary>
        /// <param name="rectangle"></param>
        /// <param name="point"></param>
        /// <returns></returns>
        public static TE_Rectangle operator +(TE_Rectangle rectangle, TE_Vector2 point)
        {
            return new TE_Rectangle(rectangle.X + point.X, rectangle.Y + point.Y, rectangle.Width, rectangle.Height);
        }

        /// <summary>
        /// Adds a vector2 to the rectangle
        /// </summary>
        /// <param name="rectangle"></param>
        /// <param name="point"></param>
        /// <returns></returns>
        public static TE_Rectangle operator +(TE_Vector2 point, TE_Rectangle rectangle)
        {
            return rectangle + point;
        }

        /// <summary>
        /// Divide each component by the grid size
        /// </summary>
        /// <returns></returns>
        public TE_Rectangle AsGridBoundRectangle()
        {
            return new TE_Rectangle(X / Game.Options.GridSize, Y / Game.Options.GridSize, Width / Game.Options.GridSize, Height / Game.Options.GridSize);
        }

        /// <summary>
        /// String representation of a rectangle
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return string.Format("[{0}, {1}, {2}, {3}]", X, Y, Width, Height);
        }

        public FloatRect ToFloatRect()
        {
            return new FloatRect(X, Y, Width, Height);
        }
    }
}